#include <func.h>
#include "Request.h"
#include "Response.h"
#include "Command.h"
#include "Crypto.h"
#include "Chunk.h"

void* send_file(void* arg) {
    Chunk* chunk = (Chunk*) arg;
    int fd = chunk->fd;  
    int connfd = chunk->connfd;
    // 1.构建 Request 对象: chunk大小，sha256sum, 服务器端存储的路径
    Request req;
    bzero(&req, sizeof(req));
    req.type = REQ_UPLOAD_FILE;

    char sha256sum[65] = "";
    sha256_chunk(chunk, sha256sum);
    
    sprintf(req.value, "%lu %s %s", chunk->size, sha256sum, chunk->path);
    req.length = strlen(req.value);
    // 2. 发送 Request 对象
    int length = 2 * sizeof(int) + req.length;
    send(connfd, &length, sizeof(int), MSG_WAITALL);
    send(connfd, &req, length, MSG_WAITALL);

    // 3. 接收 Response
    Response resp;
    bzero(&resp, sizeof(resp));
    recv(connfd, &length, sizeof(length), MSG_WAITALL);
    recv(connfd, &resp, length, MSG_WAITALL);

    switch (resp.status) {
    case RESP_NOEXIST:
        // 上传文件：读取文件时应该使用 `pread()`
    }
}

void send_chunked_file(int fd, const char* file, long fsize)
{
    int n = (fsize + CHUNK_SIZE - 1) / CHUNK_SIZE; // 向上取整
    // 创建 n 个线程，利用客户端的并行能力
    pthread_t threads[n];
    Chunk chunks[n];
    for (int i = 0; i < n; i++) {
        // 设置数据
        chunks[i].fd = fd;
        chunks[i].offset = CHUNK_SIZE * i;
        chunks[i].size = (fsize - chunks[i].offset >= CHUNK_SIZE) ? 
            CHUNK_SIZE : (fsize - chunks[i].offset);
        chunks[i].path = file;

        // 创建新的连接
        // chunks[i].connfd = tcp_connect(...);
        pthread_create(&threads[i], NULL, send_file, &chunks[i]);
    }
    // 等待线程结束
    for (int i = 0; i < n; i++) {
        pthread_join(threads[i], NULL);
    }
}

void upload_file(int connfd, const char* file)
{
    int fd = open(file, O_RDONLY);
    struct stat fstatus;
    fstat(fd, &fstatus);
    long fsize = fstatus.st_size;

    if (fsize >= 2 * CHUNK_SIZE) {
        send_chunked_file(fd, file, fsize);    
        return ;
    }    
    
    Request req;
    req.type = REQ_UPLOAD_FILE;
    // 文件大小, sha256sum, 服务器端存储的绝对路径
    char cmd[1024];
    sprintf(cmd, "sha256sum %s", file);
    FILE* pipe = popen(cmd, "r");

    char sha256sum[65] = {'\0'};
    fread(sha256sum, 1, 64, pipe);

    // 服务器端存储的路径：/username/用户的当前工作目录/filename
    char server_path[1024] = "/peanut/dir/a.txt";
    sprintf(req.value, "%ld %s %s", fsize, sha256sum, server_path);

    req.length = strlen(req.value);

    int length = 2 * sizeof(int) + req.length;
    send(connfd, &length, sizeof(int), MSG_WAITALL);
    send(connfd, &req, length, MSG_WAITALL);

    Response resp;
    recv(connfd, &length, sizeof(int), MSG_WAITALL);
    recv(connfd, &resp, length, MSG_WAITALL);

    switch (resp.status) {
    case RESP_EXIST:
        close(fd);
        break;
    case RESP_NOEXIST:
        // 发送文件内容
        char buf[4096];
        int n;
        while ((n = read(fd, buf, 4096)) > 0) {
            send(connfd, buf, n, MSG_WAITALL);
        }
        close(fd);
        break;
    }
}
